home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / Snippets / Networking / ZapTCP Application / zaptcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-27  |  7.9 KB  |  373 lines  |  [TEXT/KAHL]

  1. /*-----------------------------------------------------------------
  2.  
  3.     ZapTCP application patch sample
  4.     
  5.     Steve Falkeburg MacDTS 6/29/93
  6.     written in Think C 6.0
  7.  
  8.   -----------------------------------------------------------------*/
  9.   
  10. #ifndef __TYPES__
  11. #include <Types.h>
  12. #endif
  13.  
  14. #ifndef __MEMORY__
  15. #include <Memory.h>
  16. #endif
  17.  
  18. #ifndef __DEVICES__
  19. #include <Devices.h>
  20. #endif
  21.  
  22. #ifndef __MEMORY__
  23. #include <Memory.h>
  24. #endif
  25.  
  26. #ifndef __PACKAGES__
  27. #include <Packages.h>
  28. #endif
  29.  
  30. #ifndef __NOTIFICATION__
  31. #include <Notification.h>
  32. #endif
  33.  
  34. #ifndef __TRAPS__
  35. #include <Traps.h>
  36. #endif
  37.  
  38. #ifndef THINK_C
  39. #include <SysEqu.h>
  40. #include <strings.h>
  41. #endif
  42.  
  43. #include <MacTCPCommonTypes.h>
  44. #include <TCPPB.h>
  45.  
  46. #include <stdio.h>
  47. #include <string.h>
  48.  
  49.  
  50. /*** DEFINES ***/
  51.  
  52. #define kRAMBasedMask        (1<<6)
  53. #define kDrvrOpenMask        (1<<5)
  54. #define    kDriverNameOffset    0x12
  55.  
  56.  
  57. /*** GLOBALS ***/
  58.  
  59. static long etsAddr;    // previous trap address of _ExitToShell
  60.  
  61.  
  62. /*** PROTOTYPES ***/
  63.  
  64. pascal void ExitToShellPatch(void);
  65. OSErr ZapTCP(void);
  66. void AlertConnReleased(unsigned long remoteHost,unsigned short remotePort);
  67. void AlertStreamReleased(unsigned long stream);
  68. void LongToHex(unsigned long num,char *hexStr);
  69. void LongToIPAddr(unsigned long num,char *ipStr);
  70. void CNumToString(unsigned long num,char *str);
  71. short GetDriverRefNum(StringPtr dName,Boolean *isOpen);
  72. OSErr PostNotify(StringPtr notifStr);
  73.  
  74. /*** FUNCTIONS ***/
  75.  
  76. // installs our patch to _ExitToShell
  77. //
  78. void InstallZapTCP(void)
  79. {
  80.     long etsPatch;
  81.     
  82.     etsAddr = NGetTrapAddress(_ExitToShell,ToolTrap);
  83.     etsPatch = (long)StripAddress((Ptr)ExitToShellPatch);
  84.     NSetTrapAddress(etsPatch,_ExitToShell,ToolTrap);
  85. }
  86.  
  87.  
  88. // this is our _ExitToShell patch, which will be called when the app crashes or quits.
  89. // it even gets called on force-quits and bus errors.
  90. //
  91. pascal void ExitToShellPatch(void)
  92. {
  93.     long savedA5;
  94.     long etsNext,etsOld,ourEtsPatch;
  95.     
  96.     savedA5 = SetCurrentA5();
  97.     etsNext = etsAddr;
  98.     etsNext++;
  99.     etsNext--;            /* generate additional references so it doesn't optimize out */
  100.     ZapTCP();
  101.     SetA5(savedA5);
  102.     
  103.     // unpatch ourselves (if nobody has patched in the meantime
  104.     
  105.     etsOld = NGetTrapAddress(_ExitToShell,ToolTrap);
  106.     ourEtsPatch = (long)StripAddress((Ptr)ExitToShellPatch);
  107.     if (etsOld==ourEtsPatch) {
  108.         NSetTrapAddress(etsNext,_ExitToShell,ToolTrap);
  109.     }
  110.     
  111.     asm {
  112.         move.l    etsNext,a0
  113.         unlk    a6
  114.         move.l    a0,-(sp)
  115.         rts
  116.     }
  117. }
  118.  
  119.  
  120. // here's the patch code.  this is called on response to _ExitToShell, and searches the
  121. // list of open streams for streams in our heap.  if it finds any, those streams are released.
  122. //
  123. OSErr ZapTCP(void)
  124. {    
  125.     THz theZone;
  126.     short drvrRefNum;
  127.     OSErr err;
  128.     TCPiopb tcpBlock;
  129.     StreamPtr *curStream;
  130.     long theStream;
  131.     unsigned long streamIndex,maxStreams;
  132.     Boolean isOpen;
  133.     
  134.     theZone = ApplicZone();
  135.  
  136.     // get the MacTCP driver refnum, exiting if it never opened
  137.     
  138.     drvrRefNum = GetDriverRefNum("\p.ipp",&isOpen);
  139.     if (!isOpen)
  140.         return noErr;
  141.     
  142.     // call TCPGlobalInfo, which returns a list of the open connections and streams
  143.         
  144.     tcpBlock.ioCRefNum = drvrRefNum;
  145.     tcpBlock.csCode = TCPGlobalInfo;
  146.     err = PBControl((ParmBlkPtr)&tcpBlock,false);
  147.     if (err!=noErr)
  148.         return err;
  149.     
  150.     // check each stream to see if its buffers are in our application heap.  if so,
  151.     // release the connection via TCPAbort and TCPRelease.
  152.     
  153.     curStream = *tcpBlock.csParam.globalInfo.tcpCDBTable;
  154.     maxStreams = tcpBlock.csParam.globalInfo.tcpParamPtr->tcpMaxConn;
  155.     
  156.     for (streamIndex=0; streamIndex<maxStreams; streamIndex++,curStream++) {
  157.     
  158.         theStream = *curStream;
  159.         
  160.         if (theStream && (theStream%2)==0 && PtrZone((Ptr)theStream)==theZone) {        // only release streams in our heap 
  161.  
  162.             tcpBlock.csCode = TCPStatus;
  163.             tcpBlock.tcpStream = theStream;
  164.             err = PBControl((ParmBlkPtr)&tcpBlock,false);
  165.                 
  166.             if (err==noErr)
  167.                 AlertConnReleased(tcpBlock.csParam.status.remoteHost,(unsigned short)tcpBlock.csParam.status.remotePort);
  168.             else
  169.                 AlertStreamReleased(theStream);
  170.                 
  171.             // abort connection 
  172.             
  173.             tcpBlock.csCode = TCPAbort;
  174.             tcpBlock.tcpStream = theStream;
  175.             err = PBControl((ParmBlkPtr)&tcpBlock,false);
  176.             
  177.             // release stream
  178.             
  179.             tcpBlock.csCode = TCPRelease;
  180.             tcpBlock.tcpStream = theStream;
  181.             err = PBControl((ParmBlkPtr)&tcpBlock,false);
  182.         }
  183.     }
  184.     
  185.     return err;
  186. }
  187.  
  188.  
  189. // notify the user that a connection was closed
  190. //
  191. void AlertConnReleased(unsigned long remoteHost,unsigned short remotePort)
  192. {
  193.     char hostStr[256];
  194.     char portStr[256];
  195.     char *messageStr;
  196.     
  197.     messageStr = (char *)NewPtrSys(256);
  198.     if (MemError()!=noErr)
  199.         return;    
  200.     
  201.     LongToIPAddr(remoteHost,hostStr);
  202.     CNumToString(remotePort,portStr);
  203.     
  204.     strcpy(messageStr,"Warning: TCP connection released (remote addr: ");
  205.     strcat(messageStr,hostStr);
  206.     strcat(messageStr," remote port: ");
  207.     strcat(messageStr,portStr);
  208.     strcat(messageStr,")");
  209.     
  210.     c2pstr(messageStr);
  211.     PostNotify((StringPtr)messageStr);
  212. }
  213.  
  214.  
  215. // notify the user that a stream not associated with a connection was released
  216. //
  217. void AlertStreamReleased(unsigned long stream)
  218. {
  219.     char streamStr[256];
  220.     char *messageStr;
  221.     
  222.     messageStr = (char *)NewPtrSys(256);
  223.     if (MemError()!=noErr)
  224.         return;
  225.     
  226.     LongToHex(stream,streamStr);
  227.     
  228.     strcpy(messageStr,"Warning: TCP stream released (memory location: $");
  229.     strcat(messageStr,streamStr);
  230.     strcat(messageStr,")");
  231.  
  232.     c2pstr(messageStr);
  233.     PostNotify((StringPtr)messageStr);
  234. }
  235.  
  236.  
  237. // convert a long into a hex string for display
  238. //
  239. void LongToHex(unsigned long num,char *hexStr)
  240. {
  241.     unsigned long nibble;
  242.     short bitCount;
  243.     char hexChar[2];
  244.     
  245.     hexChar[1] = '\0';
  246.     hexStr[0] = '\0';
  247.     
  248.     for (bitCount=0; bitCount<32; bitCount+=4) {
  249.         nibble = ((num & 0xf0000000) >> 28) & 0x0000000f;
  250.         num = num << 4;
  251.         if (nibble<=9 && nibble>=0)
  252.             hexChar[0] = '0'+(char)nibble;
  253.         else if (nibble>=10 && nibble <= 15)
  254.             hexChar[0] = 0x37+(char)nibble;
  255.         else
  256.             Debugger();
  257.         strcat(hexStr,hexChar);
  258.     }
  259. }
  260.  
  261.  
  262. // convert a long into an ip address (x.x.x.x) for display
  263. //
  264. void LongToIPAddr(unsigned long num,char *ipStr)
  265. {
  266.     short bitCount;
  267.     unsigned long octet;
  268.     char octStr[256];
  269.     
  270.     ipStr[0] = '\0';
  271.     for (bitCount=0; bitCount<32; bitCount+=8) {
  272.         octet = ((num & 0xff000000) >> 24) & 0x000000ff;
  273.         num = num << 8;
  274.         CNumToString(octet,octStr);
  275.         strcat(ipStr,octStr);
  276.         if (bitCount!=24)
  277.             strcat(ipStr,".");
  278.     }
  279. }
  280.  
  281.  
  282. // convert a number into a C string for display
  283. //
  284. void CNumToString(unsigned long num,char *str)
  285. {
  286.     unsigned long place,digit;
  287.     char addStr[2];
  288.     Boolean firstDig;
  289.     
  290.     str[0] = '\0';
  291.     addStr[1] = '\0';
  292.     firstDig = true;
  293.     
  294.     for (place = 1000000000; place!=0; place = place/10) {
  295.         digit = num/place;
  296.         num -= (place*digit);
  297.         if (digit)
  298.             firstDig = false;
  299.         if (digit>0 || !firstDig || (num==0&&place==1)) {
  300.             addStr[0] = '0'+(char)digit;
  301.             strcat(str,addStr);
  302.         }
  303.     }
  304. }
  305.  
  306.  
  307. // get the refnum of a driver given its name, and tell us whether it's already open
  308. //
  309. short GetDriverRefNum(StringPtr dName,Boolean *isOpen)
  310. {
  311.     short negCount;
  312.     DCtlHandle dceH;
  313.     Ptr drivePtr;
  314.     StringPtr s;
  315.     short drvrRefNum;
  316.  
  317. #ifdef __SYSEQU__
  318.     negCount = -* (short *) (UnitNtryCnt);
  319. #else
  320.     negCount = -UnitNtryCnt;
  321. #endif
  322.  
  323.     // check to see that driver is installed, obtain refnum
  324.  
  325.     drvrRefNum = -12+1;
  326.     
  327.     do {
  328.         dceH = GetDCtlEntry(--drvrRefNum);
  329.         s = (StringPtr)"";
  330.         if ((dceH != nil) && ((**dceH).dCtlDriver!=nil)) {
  331.             if ((**dceH).dCtlFlags & kRAMBasedMask)
  332.                 drivePtr = *((Handle)(**dceH).dCtlDriver);
  333.             else
  334.                 drivePtr = (Ptr) (**dceH).dCtlDriver;
  335.             if (drivePtr!=nil) {
  336.                 s = (StringPtr)(drivePtr+kDriverNameOffset);
  337.             }
  338.         }
  339.     } while ((drvrRefNum!=negCount) && (EqualString(dName,s,false,true)==false));
  340.     
  341.     if (EqualString(dName,s,false,true)==false)
  342.         drvrRefNum = 0;
  343.     else
  344.         *isOpen = ((**dceH).dCtlFlags & kDrvrOpenMask)!=0;
  345.         
  346.     return drvrRefNum;
  347. }
  348.  
  349.  
  350. // use the notification manager to post a notification alert to the user
  351. //
  352. OSErr PostNotify(StringPtr notifStr)
  353. {
  354.     OSErr err;
  355.     NMRecPtr nmPtr;
  356.     
  357.     nmPtr = (NMRecPtr) NewPtrSys(sizeof(NMRec));
  358.     if (MemError()!=noErr)
  359.         return MemError();
  360.     
  361.     nmPtr->qType = nmType;
  362.     nmPtr->nmMark = 0;
  363.     nmPtr->nmIcon = nil;
  364.     nmPtr->nmSound = 0;
  365.     nmPtr->nmStr = notifStr;
  366.     nmPtr->nmResp = nil;
  367.     
  368.     err = NMInstall(nmPtr);
  369.     
  370.     return err;
  371. }
  372.  
  373.